using NLog;
using NLog.Config;
using NLog.Targets;
using System;
using System.IO;
using System.Runtime.CompilerServices;

namespace DidaManager.Log
{
    /// <summary>
    /// 日志管理类
    /// 支持所有级别的日志记录：Trace、Debug、Info、Warn、Error、Fatal
    /// 按日期分文件，自动清理超过10天的旧日志
    /// </summary>
    public static class LogManager
    {
        private static readonly ILogger Logger = NLog.LogManager.GetCurrentClassLogger();
        private static readonly string LogDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "logs");

        /// <summary>
        /// 初始化日志系统
        /// </summary>
        public static void Initialize()
        {
            try
            {
                // 确保日志目录存在
                if (!Directory.Exists(LogDirectory))
                {
                    Directory.CreateDirectory(LogDirectory);
                }

                // 清理旧日志文件
                CleanupOldLogs();

                // 配置 NLog
                ConfigureNLog();

                // 记录启动日志
                Logger.Info("日志系统初始化完成");
            }
            catch (Exception ex)
            {
                // 如果日志系统初始化失败，至少输出到控制台
                Console.WriteLine($"日志系统初始化失败: {ex.Message}");
            }
        }

        /// <summary>
        /// 配置 NLog - 输出所有级别的日志（Trace、Debug、Info、Warn、Error、Fatal）
        /// </summary>
        private static void ConfigureNLog()
        {
            var config = new LoggingConfiguration();

            // 创建文件目标
            var fileTarget = new FileTarget("logfile")
            {
                FileName = Path.Combine(LogDirectory, "${date:format=yyyy-MM-dd}.log"),
                Layout = "${longdate}|${level:uppercase=true}|${message}${onexception:${newline}${exception:format=tostring}}"
            };

            // 创建控制台目标
            var consoleTarget = new ConsoleTarget("logconsole")
            {
                Layout = "${time}|${level:uppercase=true}|${message}${onexception:${newline}${exception:format=tostring}}"
            };

            // 添加目标到配置
            config.AddTarget(fileTarget);
            config.AddTarget(consoleTarget);

            // 添加规则 - 使用 Trace 级别确保输出所有级别的日志
            config.LoggingRules.Add(new LoggingRule("*", LogLevel.Trace, LogLevel.Fatal, fileTarget));    // 文件输出规则：从 Trace 到 Fatal 所有级别
            config.LoggingRules.Add(new LoggingRule("*", LogLevel.Trace, LogLevel.Fatal, consoleTarget)); // 控制台输出规则：从 Trace 到 Fatal 所有级别

            // 应用配置
            NLog.LogManager.Configuration = config;
        }

        /// <summary>
        /// 清理超过10天的旧日志文件
        /// </summary>
        private static void CleanupOldLogs()
        {
            try
            {
                var cutoffDate = DateTime.Now.AddDays(-10);
                var logFiles = Directory.GetFiles(LogDirectory, "*.log");

                foreach (var file in logFiles)
                {
                    var fileInfo = new FileInfo(file);
                    if (fileInfo.CreationTime < cutoffDate)
                    {
                        try
                        {
                            File.Delete(file);
                            Console.WriteLine($"已删除旧日志文件: {file}");
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine($"删除日志文件失败 {file}: {ex.Message}");
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"清理旧日志文件时出错: {ex.Message}");
            }
        }

        /// <summary>
        /// 记录 Trace 级别日志
        /// </summary>
        /// <param name="message">日志消息</param>
        /// <param name="memberName">调用者方法名</param>
        /// <param name="sourceFilePath">调用者文件路径</param>
        /// <param name="sourceLineNumber">调用者行号</param>
        public static void Trace(string message, 
            [CallerMemberName] string memberName = "",
            [CallerFilePath] string sourceFilePath = "",
            [CallerLineNumber] int sourceLineNumber = 0)
        {
            var fileName = Path.GetFileName(sourceFilePath);
            var logMessage = $"[{fileName}:{sourceLineNumber}] {memberName}() - {message}";
            Logger.Trace(logMessage);
        }

        /// <summary>
        /// 记录 Debug 级别日志
        /// </summary>
        /// <param name="message">日志消息</param>
        /// <param name="memberName">调用者方法名</param>
        /// <param name="sourceFilePath">调用者文件路径</param>
        /// <param name="sourceLineNumber">调用者行号</param>
        public static void Debug(string message, 
            [CallerMemberName] string memberName = "",
            [CallerFilePath] string sourceFilePath = "",
            [CallerLineNumber] int sourceLineNumber = 0)
        {
            var fileName = Path.GetFileName(sourceFilePath);
            var logMessage = $"[{fileName}:{sourceLineNumber}] {memberName}() - {message}";
            Logger.Debug(logMessage);
        }

        /// <summary>
        /// 记录 Info 级别日志
        /// </summary>
        /// <param name="message">日志消息</param>
        /// <param name="memberName">调用者方法名</param>
        /// <param name="sourceFilePath">调用者文件路径</param>
        /// <param name="sourceLineNumber">调用者行号</param>
        public static void Info(string message, 
            [CallerMemberName] string memberName = "",
            [CallerFilePath] string sourceFilePath = "",
            [CallerLineNumber] int sourceLineNumber = 0)
        {
            var fileName = Path.GetFileName(sourceFilePath);
            var logMessage = $"[{fileName}:{sourceLineNumber}] {memberName}() - {message}";
            Logger.Info(logMessage);
        }

        /// <summary>
        /// 记录 Warn 级别日志
        /// </summary>
        /// <param name="message">日志消息</param>
        /// <param name="memberName">调用者方法名</param>
        /// <param name="sourceFilePath">调用者文件路径</param>
        /// <param name="sourceLineNumber">调用者行号</param>
        public static void Warn(string message, 
            [CallerMemberName] string memberName = "",
            [CallerFilePath] string sourceFilePath = "",
            [CallerLineNumber] int sourceLineNumber = 0)
        {
            var fileName = Path.GetFileName(sourceFilePath);
            var logMessage = $"[{fileName}:{sourceLineNumber}] {memberName}() - {message}";
            Logger.Warn(logMessage);
        }

        /// <summary>
        /// 记录 Error 级别日志
        /// </summary>
        /// <param name="message">日志消息</param>
        /// <param name="memberName">调用者方法名</param>
        /// <param name="sourceFilePath">调用者文件路径</param>
        /// <param name="sourceLineNumber">调用者行号</param>
        public static void Error(string message, 
            [CallerMemberName] string memberName = "",
            [CallerFilePath] string sourceFilePath = "",
            [CallerLineNumber] int sourceLineNumber = 0)
        {
            var fileName = Path.GetFileName(sourceFilePath);
            var logMessage = $"[{fileName}:{sourceLineNumber}] {memberName}() - {message}";
            Logger.Error(logMessage);
        }

        /// <summary>
        /// 记录 Error 级别日志（包含异常信息）
        /// </summary>
        /// <param name="message">日志消息</param>
        /// <param name="exception">异常对象</param>
        /// <param name="memberName">调用者方法名</param>
        /// <param name="sourceFilePath">调用者文件路径</param>
        /// <param name="sourceLineNumber">调用者行号</param>
        public static void Error(string message, Exception exception,
            [CallerMemberName] string memberName = "",
            [CallerFilePath] string sourceFilePath = "",
            [CallerLineNumber] int sourceLineNumber = 0)
        {
            var fileName = Path.GetFileName(sourceFilePath);
            var logMessage = $"[{fileName}:{sourceLineNumber}] {memberName}() - {message}";
            Logger.Error(exception, logMessage);
        }

        /// <summary>
        /// 记录 Fatal 级别日志
        /// </summary>
        /// <param name="message">日志消息</param>
        /// <param name="memberName">调用者方法名</param>
        /// <param name="sourceFilePath">调用者文件路径</param>
        /// <param name="sourceLineNumber">调用者行号</param>
        public static void Fatal(string message, 
            [CallerMemberName] string memberName = "",
            [CallerFilePath] string sourceFilePath = "",
            [CallerLineNumber] int sourceLineNumber = 0)
        {
            var fileName = Path.GetFileName(sourceFilePath);
            var logMessage = $"[{fileName}:{sourceLineNumber}] {memberName}() - {message}";
            Logger.Fatal(logMessage);
        }

        /// <summary>
        /// 记录 Fatal 级别日志（包含异常信息）
        /// </summary>
        /// <param name="message">日志消息</param>
        /// <param name="exception">异常对象</param>
        /// <param name="memberName">调用者方法名</param>
        /// <param name="sourceFilePath">调用者文件路径</param>
        /// <param name="sourceLineNumber">调用者行号</param>
        public static void Fatal(string message, Exception exception,
            [CallerMemberName] string memberName = "",
            [CallerFilePath] string sourceFilePath = "",
            [CallerLineNumber] int sourceLineNumber = 0)
        {
            var fileName = Path.GetFileName(sourceFilePath);
            var logMessage = $"[{fileName}:{sourceLineNumber}] {memberName}() - {message}";
            Logger.Fatal(exception, logMessage);
        }

        /// <summary>
        /// 记录带参数的日志
        /// </summary>
        /// <param name="level">日志级别</param>
        /// <param name="message">日志消息</param>
        /// <param name="args">参数</param>
        public static void Log(LogLevel level, string message, params object[] args)
        {
            Logger.Log(level, message, args);
        }

        /// <summary>
        /// 获取当前日志文件路径
        /// </summary>
        /// <returns>当前日志文件路径</returns>
        public static string GetCurrentLogFilePath()
        {
            return Path.Combine(LogDirectory, $"{DateTime.Now:yyyy-MM-dd}.log");
        }

        /// <summary>
        /// 获取日志目录
        /// </summary>
        /// <returns>日志目录路径</returns>
        public static string GetLogDirectory()
        {
            return LogDirectory;
        }

        /// <summary>
        /// 手动清理日志文件
        /// </summary>
        /// <param name="daysToKeep">保留天数</param>
        public static void CleanupLogs(int daysToKeep = 10)
        {
            try
            {
                var cutoffDate = DateTime.Now.AddDays(-daysToKeep);
                var logFiles = Directory.GetFiles(LogDirectory, "*.log");

                int deletedCount = 0;
                foreach (var file in logFiles)
                {
                    var fileInfo = new FileInfo(file);
                    if (fileInfo.CreationTime < cutoffDate)
                    {
                        try
                        {
                            File.Delete(file);
                            deletedCount++;
                        }
                        catch (Exception ex)
                        {
                            Error($"删除日志文件失败 {file}: {ex.Message}");
                        }
                    }
                }

                Info($"日志清理完成，删除了 {deletedCount} 个旧日志文件");
            }
            catch (Exception ex)
            {
                Error($"清理日志文件时出错: {ex.Message}");
            }
        }
    }
} 